/**
 * @param {number[]} nums
 * @return {number[][]}
 */
let threeSum = function(nums) {
    const result = [];
    nums = nums.sort((a, b) => a - b);
    if (nums && nums.length >= 3) {
        for (let i = 0; i < nums.length; i++) {
            if (i > 0 && nums[i] === nums[i - 1])
                continue;
            let item = nums[i];
            twoSum(nums, i + 1, nums.length - 1, -item)
                .map(tmp => [item].concat(tmp))
                .forEach(tmp => result.push(tmp));
        }
    }
    return result;
};

(function() {
    console.log(threeSum([-1,0,1,2,-1,-4,-2,-3,3,0,4]));
})();

function twoSum(nums, left, right, desiredValue) {
    const result = [];
    while( left < right ) {
        const value = nums[left] + nums[right];
        if ( value === desiredValue )
            result.push([nums[left], nums[right]]);
        //左移或右移动索引、且跳过重复元素
        if ( value < desiredValue )
            do left++; while (left < right && nums[left] === nums[left - 1]);
        else
            do right--; while (right > left && nums[right] === nums[right + 1]);
    }
    return result;
}